package view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;

import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import model.Container;
import model.contents.Content;
import model.contents.ContentType;
import util.IView;
import util.LoggingUtils;
import util.PlayerUtilities;
import view.content.ContentBox;
import view.transitions.TransitionBox;

public class ContainerView extends JPanel implements IView {


	private Container			container;
	private ContentBox			contentBox;
	private double				scale;

	//RBB
	protected final String className = this.getClass().getName();
	
	public ContainerView(Container c, double scale) {
		this.container = c;
		this.scale = scale;

//		System.out.println(Thread.currentThread().getName());
//		this.setBounds(PlayerUtilities.scale(this.container.getLeft(), scale),
//				PlayerUtilities.scale(this.container.getTop(), scale),
//				PlayerUtilities.scale(this.container.getWidth(), scale),
//				PlayerUtilities.scale(this.container.getHeight(), scale));

		this.setOpaque(false);
		this.setLayout(new BorderLayout());
		
		// this.showBorders();
		
		this.container.addView(this);
	}

	private void showBorders() {
		this.setBorder(BorderFactory.createLineBorder(Color.black));
	}
	
	public int getDepth() {
		return this.container.getDepth();
	}

	@Override
	public void updateView(Object obj, Object additionalInformation) {
		if (obj instanceof Container) {
			if (additionalInformation == null) {
				// TODO update the container dimensions and depth
			} else if (additionalInformation instanceof Content) {
				// System.out.println("updating content: " + additionalInformation.toString());
			}
			this.updateContainer();
		}
	}

	public void updateContainer() {
		
		final String classMethod = className + ".updateContainer()";
		LoggingUtils.logStart(classMethod);
		final double scale = ContainerView.this.scale;
		final Container container = ContainerView.this.container;
		final int x = PlayerUtilities.scale(container.getLeft(), scale);
		final int y = PlayerUtilities.scale(container.getTop(), scale);
		final int w = PlayerUtilities.scale(container.getWidth(), scale);
		final int h = PlayerUtilities.scale(container.getHeight(), scale);

		// update the container dimensions
		updateContainerDimension(container, x, y, w, h);

		// update the content box in the container
		final ContentBox cb = ContentBox.createContentBox(container.getContent(), w, h);
		this.doTransition(w, h, cb);
		try {
			LoggingUtils.logStart("invokeAndWait() of Runnable to configure ContainerView in " + classMethod);
			SwingUtilities.invokeAndWait(new Runnable() {

				@Override
				public void run() {
					LoggingUtils.logStart("run() of Runnable to configure ContainerView in " + classMethod);

					ContainerView.this.setBounds(x, y, w, h);
					if (container.getContent() != null) {

						if (cb != null) {
							if(null!=ContainerView.this.contentBox) {
								ContainerView.this.contentBox.cleanup();
							}
							ContainerView.this.removeAll();
							ContainerView.this.add(cb);
							ContainerView.this.contentBox = cb;
						} else {
							LoggingUtils.log(Level.WARNING, "Cannot play content of type " +  container.getContent().getType()
									+ " in " + classMethod);
							System.out.println("Unable to play content type: " + container.getContent().getType());
						}
					} else {
						// System.out.println("container " + container.getId() + " does not have content.");
					}
					ContainerView.this.revalidate();
					ContainerView.this.repaint();
					LoggingUtils.logEnd("run() of Runnable to configure ContainerView in " + classMethod);
				}
			});
		} catch (InterruptedException e) {
			LoggingUtils.log(Level.SEVERE, "Cannot update Container in " + classMethod
					+ " because Runnable was interrupted", e);
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			LoggingUtils.log(Level.SEVERE, "Cannot update Container in " + classMethod, e);
			e.printStackTrace();
		}
		catch (Exception e) {
			LoggingUtils.log(Level.SEVERE, "Cannot update Container in " + classMethod, e);
			e.printStackTrace();
		}
		if (cb != null) {
			
			///System.out.println("From container view ::: "+cb.getContent().getType());
			
			try
			{
				cb.play();
			}
			catch(Exception e)
			{
				LoggingUtils.log(Level.SEVERE, "Can not play "+cb.getContent().getLocalPath() + classMethod, e);
			}
		}
		LoggingUtils.logEnd(classMethod);
	}

	private void updateContainerDimension(final Container container, final int x, final int y, final int w, final int h) {
		final String classMethod = className + ".updateContainerDimension()";
		LoggingUtils.logStart(classMethod);
		if (container.getContent() == null) {
			try {
				LoggingUtils.logStart("invokeAndWait of Runnable to configure and repaint ContainerView in " + classMethod);
				SwingUtilities.invokeAndWait(new Runnable() {

					@Override
					public void run() {
						LoggingUtils.logStart("run() of Runnable to configure and repaint ContainerView in " + classMethod);
						ContainerView.this.setBounds(x, y, w, h);
						ContainerView.this.removeAll();
						ContainerView.this.revalidate();
						ContainerView.this.repaint();
						LoggingUtils.logEnd("run() of Runnable to configure and repaint ContainerView in " + classMethod);
					}
				});
			} catch (InterruptedException e) {
				LoggingUtils.log(Level.SEVERE, "Cannot run Runnable to configure and repaint ContainerView in " + classMethod, e);
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				LoggingUtils.log(Level.SEVERE, "Cannot run Runnable to configure and repaint ContainerView in " + classMethod, e);
				e.printStackTrace();
			}
			catch (Exception e) {
				LoggingUtils.log(Level.SEVERE, "Cannot run Runnable to configure and repaint ContainerView in " + classMethod, e);
				e.printStackTrace();
			}
		}
		LoggingUtils.logEnd(classMethod);
	}

	private void doTransition(final int w, final int h, final ContentBox cb) {
		// animation routine
		
		final String classMethod = className + ".doTransition(w, h, ContentBox)";
		LoggingUtils.logStart(classMethod + " with parameters (" + w + ", " + h + ")");

		final ContentBox oldContentBox = ContainerView.this.contentBox;
		if (cb == null || oldContentBox == null) {
			return;
		}
		
		try
		{
		if (oldContentBox != null) {
			if (oldContentBox.getContent().getType() == cb.getContent().getType()
					&& oldContentBox.getContent().getType() == ContentType.IMAGE) {
				// make sure we are only doing transition on images
				final TransitionBox tb = new TransitionBox(oldContentBox.getContent(), cb.getContent(), w, h, this.container.getTransition(),this.container.getTransitionType());

				try {
					LoggingUtils.logStart("invokeAndWait of Runnable to removeAll and add a TransitionBox to a ContainerView in " 
							+ classMethod);
					SwingUtilities.invokeAndWait(new Runnable() {

						@Override
						public void run() {
							LoggingUtils.logStart("run() of Runnable to removeAll and add a TransitionBox to a ContainerView in " 
									+ classMethod);
							ContainerView.this.removeAll();
							ContainerView.this.add(tb);
							LoggingUtils.logEnd("run() of Runnable to removeAll and add a TransitionBox to a ContainerView in " 
									+ classMethod);
						}
					});
				} catch (InterruptedException e) {
					LoggingUtils.log(Level.SEVERE, "Cannot run Runnable to removeAll and add a TransitionBox to a ContainerView in " 
							+ classMethod, e);
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					LoggingUtils.log(Level.SEVERE, "Cannot run Runnable to removeAll and add a TransitionBox to a ContainerView in " 
							+ classMethod, e);
					e.printStackTrace();
				}
				catch (Exception e) {
					LoggingUtils.log(Level.SEVERE, "Cannot run Runnable to removeAll and add a TransitionBox to a ContainerView in " 
							+ classMethod, e);
					e.printStackTrace();
				}
				tb.animate();
				ContainerView.this.removeAll();
			}
		}
		}catch(Exception e)
		{
			
			
		}
		LoggingUtils.logEnd(classMethod);
	}

	// clean up unnecessary resources before removing it
	public void cleanup() {
		this.container.removeView(this);
		if (this.contentBox != null) {
			this.contentBox.cleanup();
		}
	}
}
